
// CVT_64
__DefGroup CVT64 : [ALL]
  __Encoding
    field<12,  3> Pred pg=PT;
    field<15,  1> PModi pg.not=False;
    field<16,  8> Reg rd;

// I2F_64, F2I_64, F2F_64, FRND_64

__DefOptype I2F_64 : [CVT64]
  __Encoding
    field<0,  8> Optype optype==I2F_64;
    field<78, 2> FPRound rnd=RN;
    field<88, 2> FTypes ftype=F32;
    field<92, 3> FullITypes itype=S32;

  __Syntax
```asm          
I2F64{.ftype}{.itype}.rnd Rd, SrcB{.vsel}      $sched $req $wsb ;

.ftype = {.F64, .F32*, .F16, .BF16}
.itype = {.S8, .U8, .S16, .U16, .S32*, .U32, .S64, .U64}
.rnd = {.RN*, .RP, .RM, .RZ}
.vsel = {.B0, .B1, .B2, .B3, .H0, .H1}
```

  __Description
将输入整数类型转换为浮点数。

支持的类型转换包括：

| 输入类型（.itype）| 输出类型（.ftype）|
|:------------------|:-------------------|
| .S64 | .F32 / .F16 / .BF16 |
| .U64 | .F32 / .F16 / .BF16 |
| .S8 / .U8 / .S16 / .U16 / .S32* / .U32 | .F64 |

也即输入/输出类型中至少有一方是64bit位宽。

  __OperandInfo
Rd必须来源于GPR。

SrcB的来源可以是GPR、UR或cmem。

当输入整数类型位宽小于32时，SrcB可以添加一个后缀修饰符.vsel，用于选择32bit输入中的特定bit作为操作数：

- 输入整数类型为.S8/.U8时，.vsel可以取.B0（默认值）、.B1、.B2或.B3，分别用于选择32bit输入中的不同字节（.B0用于选择最低字节，.B3用于选择最高字节，以此类推）
- 输入整数类型为.S16/.U16时，.vsel可以取.H0（默认值）或.H1，分别用于选择32bit输入的低16bit或高16bit

I2F64指令的输入/输出操作数可能具有64bit位宽，关于如何表示大于32bit位宽的寄存器操作数，请参考[扩展位宽的寄存器操作数](操作数汇编显示规则.md#扩展位宽的寄存器操作数)。

  __ModifierInfo
.ftype可以是.F64、.F32（默认值，可省略）、.F16或.BF16，表示输出浮点数的类型。

.itype可以是.S8、.U8、.S16、.U16、.S32（默认值，可省略）、.U32、S64或.U64，表示输入整数的类型。

.rnd可取.RN（默认值，可省略）、.RP、.RM和.RZ，表示转换过程的舍入模式：

| .rnd  | 舍入模式 |
|:--:|:---|
|.RN | 尾数四舍五入 |
|.RP | 尾数向正无穷方向舍入 |
|.RM | 尾数向负无穷方向舍入 |
|.RZ | 尾数向零（原点）舍入 |

  __Semantics
```asm
I2F64.ftype.itype.rnd Rd, SrcB.vsel:
    if (.itype == .S16 || .itype == .U16) {
        // 将32bit输入SrcB拆分为两个16bit，h1在高位，h0在低位
        {h1, h0} = SrcB;
        // 根据.vsel选择输入
        if (.vsel == .H0) {
            b = h0;
        } else {
            b = h1;
        }
    } else if (.itype == .S8 || .itype == .U8) {
        // 将32bit输入SrcB拆分为4个byte，b3在最高位，b0在最低位
        {b3, b2, b1, b0} = SrcB;
        // 根据.vsel选择输入
        switch (.vsel) {
            case .B0: b = b0; break;
            case .B1: b = b1; break;
            case .B2: b = b2; break;
            case .B3: b = b3; break;
        }
    } else {
        b = SrcB;
    }
    // 根据舍入模式和目的数据类型，执行转换
    Rd = cvtInt2Float(b, .ftype, .rnd);
```

  __Examples
```asm
I2F64.F64.S64 R[0:1], R[2:3];   // S64 -> F64
I2F64.S64 R0, c[0x0][0x160];    // S64 -> F32
I2F64.F64.U8.RZ R[0:1], R12.B2; // U8 -> F64
```

  __Exception
    EncodingError<IllegalBitFieldCombination, "I2F_64 needs either src or dst to be 64bit."> =  (ftype!="F64") and (itype!="S64") and (itype!="U64");

__DefOpcode I2F_64_R : [I2F_64]
  __Encoding
    field<8,  4> SType stype==R;
    field<32, 8> Reg rb;
    field<82, 2> VSel rb.vsel=S0;
  __OperandInfo
    InList<pg, rb>;
    OutList<rd>;
    Order<pg, rd, rb>;
    Bitwidth<rd> = 32 + (ftype=="F64")*32;
    Bitwidth<rb> = 32 + (itype=="S64")*32 + (itype=="U64")*32;
    AsmFormat<rb.vsel> = CvtVSel(rb.vsel, itype);

__DefOpcode I2F_64_C : [I2F_64]
  __Encoding
    field<8,  4> SType stype==C;
    field<32, 22> CMem vb;
    field<82, 2> VSel vb.vsel=S0;
  __OperandInfo
    InList<pg, vb>;
    OutList<rd>;
    Order<pg, rd, vb>;
    Bitwidth<rd> = 32 + (ftype=="F64")*32;
    Bitwidth<vb> = 32 + (itype=="S64")*32 + (itype=="U64")*32;
    AsmFormat<vb.vsel> = CvtVSel(vb.vsel, itype);

__DefOpcode I2F_64_U : [I2F_64]
  __Encoding
    field<8,  4> SType stype==U;
    field<32, 6> UReg urb;
    field<82, 2> VSel urb.vsel=S0;
  __OperandInfo
    InList<pg, urb>;
    OutList<rd>;
    Order<pg, rd, urb>;
    Bitwidth<rd> = 32 + (ftype=="F64")*32;
    Bitwidth<urb> = 32 + (itype=="S64")*32 + (itype=="U64")*32;
    AsmFormat<urb.vsel> = CvtVSel(urb.vsel, itype);

__DefOptype F2F_64 : [CVT64]
  __Encoding
    field<0,  8> Optype optype==F2F_64;
    field<78,  2> FPRound rnd = RN;
    field<88,  2> FTypes dsttype;
    field<92,  2> FTypes srctype;

  __Syntax
```asm          
F2F64.dsttype.srctype{.rnd} Rd, {-}{|}SrcB{.hsel}{|}      $sched $req $wsb ;

.dsttype = {.F64, .F32, .F16, .BF16}
.srctype = {.F64, .F32, .F16, .BF16}
.rnd = {.RN*, .RP, .RM, .RZ}
.hsel = {.H0*, .H1}
```

  __Description
将srctype类型的输入浮点数SrcB转换为dsttype类型的浮点数Rd。

支持的类型转换包括：

| 输入类型（.srctype）| 输出类型（.dsttype）|
|:------------------|:-------------------|
| .F64 | .F32 / .F16 / .BF16 |
| .F32 / .F16 / .BF16 | .F64 |

也即在双精度类型与其他低精度类型之间互相转换。

  __OperandInfo
    ModiOrder<dsttype, srctype>;
  
Rd必须来源于GPR。

SrcB的来源可以是GPR、UR或cmem。

SrcB可以添加3种可选的修饰符（可共存）：

- 负号前缀（-）：表示对SrcB取相反数作为输入。
- 绝对值（|*|）：表示取SrcB的绝对值作为输入。
- bitfield选择（.hsel）：仅当.srctype = .F16或.BF16时生效，可取值为.H0（默认值）或.H1，分别表示从SrcB的32bit中提取低16bit或是高16bit作为输入。

SrcB同时存在多种修饰符时，按照：先.hsel，再取绝对值，最后取相反数的优先级次序与SrcB结合。

  __ModifierInfo
.dsttype可取值包括.F64、.F32、.F16、.BF16，表示转换目的类型。

.srctype可取值包括.F32、.F16、.BF16，表示转换来源类型。

.rnd可取.RN（默认值，可省略）、.RP、.RM和.RZ，表示转换过程的舍入模式：

| .rnd  | 舍入模式 |
|:--:|:---|
|.RN | 尾数四舍五入 |
|.RP | 尾数向正无穷方向舍入 |
|.RM | 尾数向负无穷方向舍入 |
|.RZ | 尾数向零（原点）舍入 |

根据浮点数的定义，从低于双精度的类型转换到双精度是完全精确的，不会发生舍入。

  __Semantics
```asm
F2F64.dsttype.srctype.rnd Rd, SrcB.hsel:
    if (.srctype == .F16 || .srctype == .BF16) {
        // 将32bit输入SrcB拆分为两个16bit，h1在高位，h0在低位
        {h1, h0} = SrcB;
        // 根据.hsel选择输入
        if (.hsel == .H0) {
            b = h0;
        } else {
            b = h1;
        }
    } else {
        b = SrcB;
    }
    // 将b转换为指定格式的浮点数，根据需要进行附加处理
    Rd = cvtFP2FP(b, .dsttype, .rnd);
```

  __Examples
```asm
F2F64.F64.F32 R[0:1], -|R[12:13]|;  // F32 -> F64（精确转换）
F2F64.F16.F64.RZ R5, R[0:1];        // F64 -> F16（有潜在舍入误差）
```
  __Exception
    EncodingError<IllegalBitFieldCombination, "F2F_64 needs either src or dst to be 64bit."> =  (dsttype!="F64") and (srctype!="F64");

__DefOpcode F2F_64_R : [F2F_64]
  __Encoding
    field<8,  4> SType stype==R;
    field<32, 8> Reg rb;
    field<96, 1> SignModi rb.neg=False;
    field<97, 1> SignModi rb.abs=False;
    field<82, 1> HSel rb.hsel=H0;
  __OperandInfo
    InList<pg, rb>;
    OutList<rd>;
    Order<pg, rd, rb>;
    Bitwidth<rd> = 32 + (dsttype=="F64")*32;
    Bitwidth<rb> = 32 + (srctype=="F64")*32;

__DefOpcode F2F_64_U : [F2F_64]
  __Encoding
    field<8,  4> SType stype==U;
    field<32, 6> UReg urb;
    field<96, 1> SignModi urb.neg=False;
    field<97, 1> SignModi urb.abs=False;

    field<82, 1> HSel urb.hsel=H0;
  __OperandInfo
    InList<pg, urb>;
    OutList<rd>;
    Order<pg, rd, urb>;
    Bitwidth<rd>  = 32 + (dsttype=="F64")*32;
    Bitwidth<urb> = 32 + (srctype=="F64")*32;

__DefOpcode F2F_64_C : [F2F_64]
  __Encoding
    field<8,  4> SType stype==C;
    field<32, 22> CMem vb;
    field<96, 1> SignModi vb.neg=False;
    field<97, 1> SignModi vb.abs=False;

    field<82,  1> HSel vb.hsel=H0;
  __OperandInfo
    InList<pg, vb>;
    OutList<rd>;
    Order<pg, rd, vb>;
    Bitwidth<rd> = 32 + (dsttype=="F64")*32;
    Bitwidth<vb> = 32 + (srctype=="F64")*32;

__DefOptype F2I_64 : [CVT64]
  __Encoding
    field<0,  8> Optype optype==F2I_64;
    field<77, 1> F2INTZ ntz=NoNTZ;
    field<78, 2> F2IRnd rnd=ROUND;
    field<80, 1> FPSat  sat=NoSAT;
    field<88, 3> FullITypes itype=S32;
    field<92, 2> FTypes ftype=F32;
  
  __Syntax
```asm          
F2I64.itype.ftype{.NTZ}{.rnd} Rd, {-}{|}SrcB{.hsel}{|}      $sched $req $wsb ;

.itype = {.S8, .U8, .S16, U16, S32*, .U32, .S64, .U64}
.ftype = {.F64, .F32*, .F16, .BF16}
.rnd = {.ROUND*, .CEIL, .FLOOR, .TRUNC}
.hsel = {.H0*, .H1}
```

  __Description
将ftype类型的输入浮点数SrcB根据指定的方式转换为整数，并写入Rd。

支持的类型转换包括：

| 输入类型（.ftype）| 输出类型（.itype）|
|:------------------|:-------------------|
| .F32 / .F16 / .BF16 | .U64 / .S64 |
| .F64 | .S8 / .U8 / .S16 / .U16 / .S32* / .U32 |
| .F64 | .U64 / .S64 |

如果转换的目的类型位宽小于32bit，根据结果的符号进行零扩展或符号扩展，以填满Rd。

  __OperandInfo
Rd必须来源于GPR。

SrcB的来源可以是GPR、UR或cmem。

SrcB可以添加3种可选的修饰符（可共存）：

- 负号前缀（-）：表示对SrcB取相反数作为输入。
- 绝对值（|*|）：表示取SrcB的绝对值作为输入。
- bitfield选择（.hsel）：仅当.ftype = .F16或.BF16时生效，可取值为.H0（默认值）或.H1，分别表示从SrcB的32bit中提取低16bit或是高16bit作为输入。

SrcB同时存在多种修饰符时，按照：先.hsel，再取绝对值，最后取相反数的优先级次序与SrcB结合。

  __ModifierInfo
.itype可取值包括.S8、.U8、.S16、U16、S32（默认可省略）、.U32、U64或S64，表示转换的目的类型。

.ftype可取值包括.F64、.F32（默认可省略）、.F16、.BF16，表示转换的来源类型。

.rnd可取值包括.ROUND（默认可省略）、.CEIL、.FLOOR和.TRUNC，分别表示舍入模式为：向最近的整数舍入（如果等距，向偶数舍入）、向正无穷方向舍入、向负无穷方向舍入和向零舍入。

可选修饰符.NTZ表示若SrcB为NAN，将其转换为0。

  __Semantics
```asm
F2I64.itype.ftype.ntz.rnd Rd, SrcB.hsel:
    if (.ftype == .F16 || .ftype == .BF16) {
        // 将32bit输入SrcB拆分为两个16bit，h1在高位，h0在低位
        {h1, h0} = SrcB;
        // 根据.hsel选择输入
        if (.hsel == .H0) {
            b = h0;
        } else {
            b = h1;
        }
    } else {
        b = SrcB;
    }
    // 获取转换的目的类型的位宽
    n = sizeInBitOf(.itype);
    // 将b转换为整数
    if (b is not NAN) {
        // 根据.rnd舍入转换为整数
        b = round2Int(b, .rnd);
        // 将结果饱和转换到.itype的最大最小值之间
        b = b > MAX(.itype) ? MAX(.itype) : b;
        b = b < MIN(.itype) ? MIN(.itype) : b;
        // 若n < 32，需要零扩展/符号扩展到32bit
        if (n < 32) {
            if (.itype is signed) {
                // 符号扩展到32bit
                Rd = INT32(b);
            } else {
                // 零扩展到32bit
                Rd = UINT32(b);
            }
        }
    // 处理NAN输入
    } else {
        if (.ntz == .NTZ) {
            // Rd所有bit置零
            Rd[(n-1):0] = 0;
        } else {
            // Rd的MSB置1，其余bit置零
            Rd[(n-1):0] = 1 << (n-1);
        }
    }
```

  __Examples
```asm
F2I64.S8.F64 R0, -|R1|;         // F64 -> S8
F2I64.S64.F16.FLOOR R0, R1.H1;  // F16 -> S64
```
  __Exception
    EncodingError<IllegalBitFieldCombination, "F2I_64 needs either src or dst to be 64bit."> =  (ftype!="F64") and (itype!="S64") and (itype!="U64");

__DefOpcode F2I_64_R : [F2I_64]
  __Encoding
    field<8,  4> SType stype==R;
    field<32, 8> Reg rb;
    field<96, 1> SignModi rb.neg=False;
    field<97, 1> SignModi rb.abs=False;

    field<82, 1> HSel rb.hsel=H0;
  __OperandInfo
    InList<pg, rb>;
    OutList<rd>;
    Order<pg, rd, rb>;
    Bitwidth<rd> = 32 + (itype=="S64")*32 + (itype=="U64")*32;
    Bitwidth<rb> = 32 + (ftype=="F64")*32;

__DefOpcode F2I_64_U : [F2I_64]
  __Encoding
    field<8,  4> SType stype==U;
    field<32, 6> UReg urb;
    field<96, 1> SignModi urb.neg=False;
    field<97, 1> SignModi urb.abs=False;

    field<82, 1> HSel urb.hsel=H0;
  __OperandInfo
    InList<pg, urb>;
    OutList<rd>;
    Order<pg, rd, urb>;
    Bitwidth<rd> = 32 + (itype=="S64")*32 + (itype=="U64")*32;
    Bitwidth<urb> = 32 + (ftype=="F64")*32;

__DefOpcode F2I_64_C : [F2I_64]
  __Encoding
    field<8,  4> SType stype==C;
    field<32, 22> CMem vb;
    field<96, 1> SignModi vb.neg=False;
    field<97, 1> SignModi vb.abs=False;

    field<82, 1> HSel vb.hsel=H0;
  __OperandInfo
    InList<pg, vb>;
    OutList<rd>;
    Order<pg, rd, vb>;
    Bitwidth<rd> = 32 + (itype=="S64")*32 + (itype=="U64")*32;
    Bitwidth<vb> = 32 + (ftype=="F64")*32;

__DefOptype FRND_64 : [CVT64]
  __Encoding
    field<0,  8> Optype optype==FRND_64;
    field<76, 1> FPFtz ftz=NoFTZ;
    field<78, 2> F2IRnd rnd=ROUND;
    field<88, 2> F64Only ftype==F64;
  
  __Syntax
```asm          
FRND64{.FTZ}{.rnd} Rd, {-}{|}SrcB{|}      $sched $req $wsb ;

.rnd = {.ROUND*, .CEIL, .FLOOR, .TRUNC}
```

  __Description
将双精度浮点数SrcB根据指定的方式转换为整数，再以双精度浮点数保存在Rd中。

由于输入SrcB已经是浮点数，因此取整本身不会溢出，只会得到一个能用浮点数表示的整数。

  __OperandInfo
Rd必须来源于GPR。

SrcB的来源可以是GPR、UR或cmem。

SrcB可以添加2种可选的修饰符（可共存）：

- 负号前缀（-）：表示对SrcB取相反数作为输入。
- 绝对值（|*|）：表示取SrcB的绝对值作为输入。

  __ModifierInfo
.rnd可取值包括.ROUND（默认可省略）、.CEIL、.FLOOR和.TRUNC，分别表示舍入模式为：向最近的整数舍入（如果等距，向偶数舍入）、向正无穷方向舍入、向负无穷方向舍入和向零舍入。

可选修饰符.FTZ表示：若SrcB为非规格化浮点数，转换为0。

  __Semantics
如果输入浮点数操作数为NAN，该指令的输出行为参考[浮点数NAN处理规则](浮点数NAN处理规则.md#输入操作数含有nan)。

```asm
FRND64.ftz.rnd Rd, SrcB:
    // 处理输入NAN
    if (SrcB is NAN) {
        // 输出一个与SrcB有关的QNAN：指数部分全1，尾数部分MSB为1，其他所有bit与SrcB相同
        Rd[63:0] = QNAN(SrcB);
    }
    // 处理非规格化输入
    else if (.ftz == .FTZ && SrcB is subnormal) {
        Rd[63:0] = 0;
    }
    // 将b转换为整数
    else {
        Rd = round2Int64(SrcB, .rnd);
    }
```

  __Examples
```asm
FRND64 R0, -|R1|;
```

__DefOpcode FRND_64_R : [FRND_64]
  __Encoding
    field<8,  4> SType stype==R;
    field<32, 8> Reg rb;
    field<96, 1> SignModi rb.neg=False;
    field<97, 1> SignModi rb.abs=False;

  __OperandInfo
    InList<pg, rb>;
    OutList<rd>;
    Order<pg, rd, rb>;
    Bitwidth<rd> = 64;
    Bitwidth<rb> = 64;

__DefOpcode FRND_64_U : [FRND_64]
  __Encoding
    field<8,  4> SType stype==U;
    field<32, 6> UReg urb;
    field<96, 1> SignModi urb.neg=False;
    field<97, 1> SignModi urb.abs=False;

  __OperandInfo
    InList<pg, urb>;
    OutList<rd>;
    Order<pg, rd, urb>;
    Bitwidth<rd> = 64;
    Bitwidth<urb> = 64;

__DefOpcode FRND_64_C : [FRND_64]
  __Encoding
    field<8,  4> SType stype==C;
    field<32, 22> CMem vb;
    field<96, 1> SignModi vb.neg=False;
    field<97, 1> SignModi vb.abs=False;
  __OperandInfo
    InList<pg, vb>;
    OutList<rd>;
    Order<pg, rd, vb>;
    Bitwidth<rd> = 64;
    Bitwidth<vb> = 64;
